<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Minesweeper
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora058.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora061.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Minesweeper</H2>
<A NAME="sec-demin"></A>
Let us briefly recall the object of this game: to explore a mine
field without stepping on one.
A mine field is a two dimensional array (a matrix) where some cells
contain hidden mines while others are empty. At the beginning of the
game, all the cells are closed and the player must open them one
after another. The player wins when he opens all the cells that
are empty.<BR>
<BR>
Every turn, the player may open a cell or flag it as
containing a mine. If he opens a cell that contains a mine, it
blows up and the player loses. If the cell is empty, its appearance is
modified and the number of mines in the 8 neighbor cells is displayed
(thus at most 8). If the player decides to flag a cell, he cannot
open it until he removes the flag.<BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora024.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 6.5: Screenshot.</DIV><BR>

<A NAME="fig-demineur-ecran"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>We split the implementation of the game into three parts.
<OL type=1>
<LI>
 The abstract game, including the internal
 representation of the mine field as well as the functions
 manipulating this representation.

<LI> The graphical part of the game,
 including the function for displaying cells.

<LI> The interaction between the program and the player.
</OL><A NAME="toc86"></A>
<H3> The abstract mine field</H3>This part deals with the mine field as an abstraction only, and does
not address its display.<BR>
<BR>
<A NAME="demin-data-types"></A><BR>
<BR>

<H5> Configuration</H5> A mine field is defined by its dimensions
and the number of mines it contains. We group these three pieces of
data in a record and define a default configuration: 10�10
cells and 15 mines.


<PRE><BR># <B>type</B><CODE> </CODE>config<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>nbcols<CODE> </CODE><CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>nbrows<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>nbmines<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE> </CODE>};;<BR># <B>let</B><CODE> </CODE>default_config<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>nbcols<CODE>=</CODE><CODE>1</CODE><CODE>0</CODE>;<CODE> </CODE>nbrows<CODE>=</CODE><CODE>1</CODE><CODE>0</CODE>;<CODE> </CODE>nbmines<CODE>=</CODE><CODE>1</CODE><CODE>5</CODE><CODE> </CODE>}<CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>

<H5> The mine field</H5>
It is natural to represent the mine field as a two dimensional array.
However, it is still necessary to specify what the cells are, and what
information their encoding should provide. The state of a cell should
answer the following questions:
<UL>
<LI>
 is there a mine in this cell?

<LI> is this cell opened (has it been seen)?

<LI> is this cell flagged?

<LI> how many mines are there in neighbor cells?
</UL>
The last item is not mandatory, as it is possible to compute
it when it is needed. However, it is simpler to do this computation
once at the beginning of the game.<BR>
<BR>
We represent a cell with a record that contains these four pieces of data.


<PRE><BR># <B>type</B><CODE> </CODE>cell<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>mined<CODE> </CODE><CODE>:</CODE><CODE> </CODE>bool<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>seen<CODE> </CODE><CODE>:</CODE><CODE> </CODE>bool<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>flag<CODE> </CODE><CODE>:</CODE><CODE> </CODE>bool<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>nbm<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE>}<CODE> </CODE>;;<BR>

</PRE>

The two dimensional array is an array of arrays of cells:


<PRE><BR># <B>type</B><CODE> </CODE>board<CODE> </CODE><CODE>=</CODE><CODE> </CODE>cell<CODE> </CODE>array<CODE> </CODE>array<CODE> </CODE><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>

<H5> An iterator</H5>
In the rest of the program, we often need to iterate a function over all
the cells of the mine field. To do it generically, we define the
operator <TT>iter_cells</TT> that applies the function <TT>f</TT>,
given as an argument, to each cell of the board defined by the
configuration <TT>cf</TT>.


<PRE><BR># <B>let</B><CODE> </CODE>iter_cells<CODE> </CODE>cf<CODE> </CODE>f<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>for</B><CODE> </CODE>i<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>to</B><CODE> </CODE>cf<CODE>.</CODE>nbcols<CODE>-</CODE><CODE>1</CODE><CODE> </CODE><B>do</B><CODE> </CODE><B>for</B><CODE> </CODE>j<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>to</B><CODE> </CODE>cf<CODE>.</CODE>nbrows<CODE>-</CODE><CODE>1</CODE><CODE> </CODE><B>do</B><CODE> </CODE>f<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><B>done</B><CODE> </CODE><B>done</B><CODE> </CODE>;;<BR><CODE>val iter_cells : config -&gt; (int * int -&gt; 'a) -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
This is a good example of a mix between functional and imperative
programming styles, as we use a higher order function (a function
taking another function as an argument) to iterate a function that
operates through side effects (as it returns no value).<BR>
<BR>

<H5> Initialization</H5>
We randomly choose which cells are mines. If <I>c</I> and <I>r</I> are
respectively the number of columns and rows of the mine field, and <I>m</I>
the number of mines, we need to generate <I>m</I> different numbers between
1 and <I>c</I>� <I>r</I>. We suppose that <I>m</I> <FONT FACE=symbol>�</FONT> <I>c</I>� <I>r</I> to define the
algorithm, but the program using it will need to check this condition.<BR>
<BR>
The straightforward algorithm consists of starting with an empty list,
picking a random number and putting it in the list if it is not there
already, and repeating this until the list contains <I>m</I> numbers. We
use the following functions from the <TT>Random</TT> and
<TT>Sys</TT> modules:
<A NAME="@fonctions185"></A>
<A NAME="@fonctions186"></A>
<A NAME="@fonctions187"></A>
<UL>
<LI>
 <TT>Random.int</TT>: <I>int -&gt; int</I>, picks a number
 between 0 and <I>n</I>-1 (<I>n</I> is the argument) according to a random
 number generator; 

<LI> <TT>Random.init</TT>: <I>int -&gt; unit</I>, initializes the
 random number generator;

<LI> <TT>Sys.time</TT>: <I>unit -&gt; float</I>, returns the number
 of milliseconds of processor time the program used since it
 started. This function will be used to initialize the random number
 generator with a different seed for each game.
</UL>
The modules containing these functions are described in more details
in chapter&nbsp;<A HREF="index.html#chap-Bibliotheques">8</A>, pages&nbsp;<A HREF="book-ora076.html#sec-mod-random">??</A>
and&nbsp;<A HREF="book-ora076.html#sec-mod-sys">??</A>.<BR>
<BR>
The random mine placement function receives the number of cells
(<TT>cr</TT>) and the number of mines to place (<TT>m</TT>), and returns
a list of linear positions for the <TT>m</TT> mines.


<PRE><BR># <B>let</B><CODE> </CODE>random_list_mines<CODE> </CODE>cr<CODE> </CODE>m<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cell_list<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE>[]<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>while</B><CODE> </CODE><TT>(</TT>List.length<CODE> </CODE><CODE>!</CODE>cell_list<TT>)</TT><CODE> </CODE><CODE>&lt;</CODE><CODE> </CODE>m<CODE> </CODE><B>do</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Random.int<CODE> </CODE>cr<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>not<CODE> </CODE><TT>(</TT>List.mem<CODE> </CODE>n<CODE> </CODE><CODE>!</CODE>cell_list<TT>)</TT><CODE> </CODE><B>then</B><CODE> </CODE>cell_list<CODE> </CODE><CODE>:=</CODE><CODE> </CODE>n<CODE> </CODE>::<CODE> </CODE><CODE>!</CODE>cell_list<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>!</CODE>cell_list<CODE> </CODE>;;<BR><CODE>val random_list_mines : int -&gt; int -&gt; int list = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
With such an implementation, there is no upper bound on the number of
steps the function takes to terminate. If the random number generator
is reliable, we can only insure that the probability it does not
terminate is zero. However, all experimental uses of this function have
never failed to terminate. Thus, even though it is not guaranteed that it
will terminate, we will use it to generate the list of mined cells.<BR>
<BR>
We need to initialize the random number generator so that each run of
the game does not use the same mine field. We use the processor time
since the beginning of the program execution to initialize the random
number generator.


<PRE><BR># <B>let</B><CODE> </CODE>generate_seed<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Sys.time<CODE> </CODE>()<CODE> </CODE><B>in</B><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>int_of_float<CODE> </CODE><TT>(</TT>t<CODE>*.</CODE><CODE>1</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>.</CODE><CODE>0</CODE><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Random.init<TT>(</TT>n<CODE> </CODE><B>mod</B><CODE> </CODE><CODE>1</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><TT>)</TT><CODE> </CODE>;;<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE>val generate_seed : unit -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>

In practice, a given program very often takes the same execution time,
which results in a similar result for <TT>generate_seed</TT> for each
run. We ought to use the <TT>Unix.time</TT> function (see
chapter&nbsp;<A HREF="index.html#chap-PS">18</A>).<BR>
<BR>
We very often need to know the neighbors of a given cell, during the
initialization of the mine field as well as during the game. Thus we
write a <TT>neighbors</TT> function. This function must take into
account the side and corner cells that have fewer neighbors than the
middle ones (function <TT>valid</TT>).


<PRE><BR># <B>let</B><CODE> </CODE>valid<CODE> </CODE>cf<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>i<CODE>&gt;=</CODE><CODE>0</CODE><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>i<CODE>&lt;</CODE>cf<CODE>.</CODE>nbcols<CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>j<CODE>&gt;=</CODE><CODE>0</CODE><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>j<CODE>&lt;</CODE>cf<CODE>.</CODE>nbrows<CODE> </CODE><CODE> </CODE>;;<BR><CODE>val valid : config -&gt; int * int -&gt; bool = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>neighbors<CODE> </CODE>cf<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ngb<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>[</CODE>x<CODE>-</CODE><CODE>1</CODE><CODE>,</CODE>y<CODE>-</CODE><CODE>1</CODE>;<CODE> </CODE>x<CODE>-</CODE><CODE>1</CODE><CODE>,</CODE>y;<CODE> </CODE>x<CODE>-</CODE><CODE>1</CODE><CODE>,</CODE>y<CODE>+</CODE><CODE>1</CODE>;<CODE> </CODE>x<CODE>,</CODE>y<CODE>-</CODE><CODE>1</CODE>;<CODE> </CODE>x<CODE>,</CODE>y<CODE>+</CODE><CODE>1</CODE>;<CODE> </CODE>x<CODE>+</CODE><CODE>1</CODE><CODE>,</CODE>y<CODE>-</CODE><CODE>1</CODE>;<CODE> </CODE>x<CODE>+</CODE><CODE>1</CODE><CODE>,</CODE>y;<CODE> </CODE>x<CODE>+</CODE><CODE>1</CODE><CODE>,</CODE>y<CODE>+</CODE><CODE>1</CODE><CODE>]</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>List.filter<CODE> </CODE><TT>(</TT>valid<CODE> </CODE>cf<TT>)</TT><CODE> </CODE>ngb<CODE> </CODE>;;<BR><CODE>val neighbors : config -&gt; int * int -&gt; (int * int) list = &lt;fun&gt;</CODE><BR>

</PRE>

The <TT>initialize_board</TT> function creates the initial mine
field. It proceeds in four steps:
<OL type=1>
<LI>
 generation of the list of mined cells;

<LI> creation of a two dimensional array containing different cells;

<LI> setting of mined cells in the board;

<LI> computation of the number of mines in neighbor cells for each
 cell that is not mined.
</OL>The function <TT>initialize_board</TT> uses a few local functions
that we briefly describe.
<DL COMPACT=compact>
<DT>
<TT>cell_init</TT><DD>: creates an initial cell value;

<DT><TT>copy_cell_init</TT><DD>: puts a copy of the initial cell
 value in a cell of the board;

<DT><TT>set_mined</TT><DD>: puts a mine in a cell;

<DT><TT>count_mined_adj</TT><DD>: computes the number of mines in the
 neighbors of a given cell;

<DT><TT>set_count</TT><DD>: updates the number of mines in the neighbors
 of a cell if it is not mined.
</DL>


<PRE><BR># <B>let</B><CODE> </CODE>initialize_board<CODE> </CODE>cf<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cell_init<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>mined<CODE>=</CODE><B>false</B>;<CODE> </CODE>seen<CODE>=</CODE><B>false</B>;<CODE> </CODE>flag<CODE>=</CODE><B>false</B>;<CODE> </CODE>nbm<CODE>=</CODE><CODE>0</CODE><CODE> </CODE>}<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>copy_cell_init<CODE> </CODE>b<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>b<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>cell_init()<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>set_mined<CODE> </CODE>b<CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>b<CODE>.</CODE><TT>(</TT>n<CODE> </CODE><CODE>/</CODE><CODE> </CODE>cf<CODE>.</CODE>nbrows<TT>)</TT><CODE>.</CODE><TT>(</TT>n<CODE> </CODE><B>mod</B><CODE> </CODE>cf<CODE>.</CODE>nbrows<TT>)</TT><CODE>.</CODE>mined<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><B>true</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>count_mined_adj<CODE> </CODE>b<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>ref<CODE> </CODE><CODE>0</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>inc_if_mined<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>if</B><CODE> </CODE>b<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>mined<CODE> </CODE><B>then</B><CODE> </CODE>incr<CODE> </CODE>x<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>List.iter<CODE> </CODE>inc_if_mined<CODE> </CODE><TT>(</TT>neighbors<CODE> </CODE>cf<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>!</CODE>x<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>set_count<CODE> </CODE>b<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>not<CODE> </CODE>b<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>mined<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE>b<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>nbm<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>count_mined_adj<CODE> </CODE>b<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>list_mined<CODE> </CODE><CODE>=</CODE><CODE> </CODE>random_list_mines<CODE> </CODE><TT>(</TT>cf<CODE>.</CODE>nbcols<CODE>*</CODE>cf<CODE>.</CODE>nbrows<TT>)</TT><CODE> </CODE>cf<CODE>.</CODE>nbmines<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>board<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Array.make_matrix<CODE> </CODE>cf<CODE>.</CODE>nbcols<CODE> </CODE>cf<CODE>.</CODE>nbrows<CODE> </CODE><TT>(</TT>cell_init<CODE> </CODE>()<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>iter_cells<CODE> </CODE>cf<CODE> </CODE><TT>(</TT>copy_cell_init<CODE> </CODE>board<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.iter<CODE> </CODE><TT>(</TT>set_mined<CODE> </CODE>board<TT>)</TT><CODE> </CODE>list_mined<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>iter_cells<CODE> </CODE>cf<CODE> </CODE><TT>(</TT>set_count<CODE> </CODE>board<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>board<CODE> </CODE>;;<BR><CODE>val initialize_board : config -&gt; cell array array = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Opening a cell</H5>
During a game, when the player opens a cell whose neighbors are empty
(none contains a mine), he knows that he can open the neighboring
cells without risk, and he can keep opening cells as long as he opens
cells without any mined neighbor. In order to relieve the player of
this boring process (as it is not challenging at all), our
Minesweeper opens all these cells itself. To this end, we write the
function <TT>cells_to_see</TT> that returns a list of all the
cells to open when a given cell is opened.<BR>
<BR>
The algorithm needed is simple to state: if the opened cell has some
neighbors that contain a mine, then the list of cells to see consists
only of the opened cell; otherwise, the list of cells to see consists
of the neighbors of the opened cell, as well as the lists of cells to
see of these neighbors. The difficulty is in writing a program that
does not loop, as every cell is a neighbor of any of its neighbors. We
thus need to avoid processing the same cell twice.<BR>To remember which cells were processed, we use the array of booleans
<TT>visited</TT>. Its size is the same as the mine field. The value
<B>true</B> for a cell of this array denotes that it was already
visited. We recurse only on cells that were not visited.<BR>
<BR>
We use the auxiliary function <TT>relevant</TT> that computes two sublists
 from the list of neighbors of a cell. Each one of these lists
only contains cells that do not contain a mine, that are not opened,
that are not flagged by the player, and that were not visited. The
first sublist is the list of neighboring cells who have at least one
neighbor containing a mine; the second sublist is the list of
neighboring cells whose neighbors are all empty. As these lists are
computed, all these cells are marked as visited. Notice that flagged
cells are not processed, as a flag is meant to prevent opening a
cell.<BR>
<BR>
The local function <TT>cells_to_see_rec</TT> implements the
recursive search loop. It takes as an argument the list of cells to
visit, updates it, and returns the list of cells to open.
This function is called with the list consisting only of the cell
being opened, after it is marked as visited.


<PRE><BR># <B>let</B><CODE> </CODE>cells_to_see<CODE> </CODE>bd<CODE> </CODE>cf<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>visited<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Array.make_matrix<CODE> </CODE>cf<CODE>.</CODE>nbcols<CODE> </CODE>cf<CODE>.</CODE>nbrows<CODE> </CODE><B>false</B><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE><B>rec</B><CODE> </CODE>relevant<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>function</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>[]<CODE> </CODE>-&gt;<CODE> </CODE><TT>(</TT><CODE>[],[]</CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><TT>(</TT><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE><B>as</B><CODE> </CODE>c<TT>)</TT>::t<CODE> </CODE>-&gt;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cell<CODE>=</CODE>bd<CODE>.</CODE><TT>(</TT>x<TT>)</TT><CODE>.</CODE><TT>(</TT>y<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>if</B><CODE> </CODE>cell<CODE>.</CODE>mined<CODE> </CODE><CODE>||</CODE><CODE> </CODE>cell<CODE>.</CODE>flag<CODE> </CODE><CODE>||</CODE><CODE> </CODE>cell<CODE>.</CODE>seen<CODE> </CODE><CODE>||</CODE><CODE> </CODE>visited<CODE>.</CODE><TT>(</TT>x<TT>)</TT><CODE>.</CODE><TT>(</TT>y<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE>relevant<CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><B>let</B><CODE> </CODE><TT>(</TT>l1<CODE>,</CODE>l2<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>relevant<CODE> </CODE>t<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>visited<CODE>.</CODE><TT>(</TT>x<TT>)</TT><CODE>.</CODE><TT>(</TT>y<TT>)</TT><CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><B>true</B><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>cell<CODE>.</CODE>nbm<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>then</B><CODE> </CODE><TT>(</TT>l1<CODE>,</CODE>c::l2<TT>)</TT><CODE> </CODE><B>else</B><CODE> </CODE><TT>(</TT>c::l1<CODE>,</CODE>l2<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE><B>rec</B><CODE> </CODE>cells_to_see_rec<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>function</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>[]<CODE> </CODE>-&gt;<CODE> </CODE>[]<CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><TT>(</TT><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE><B>as</B><CODE> </CODE>c<TT>)</TT>::t<CODE> </CODE>-&gt;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>bd<CODE>.</CODE><TT>(</TT>x<TT>)</TT><CODE>.</CODE><TT>(</TT>y<TT>)</TT><CODE>.</CODE>nbm<CODE>&lt;&gt;</CODE><CODE>0</CODE><CODE> </CODE><B>then</B><CODE> </CODE>c<CODE> </CODE>::<CODE> </CODE><TT>(</TT>cells_to_see_rec<CODE> </CODE>t<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><B>let</B><CODE> </CODE><TT>(</TT>l1<CODE>,</CODE>l2<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>relevant<CODE> </CODE><TT>(</TT>neighbors<CODE> </CODE>cf<CODE> </CODE>c<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><CODE> </CODE><TT>(</TT>c<CODE> </CODE>::<CODE> </CODE>l1<TT>)</TT><CODE> </CODE><CODE> </CODE><CODE>@</CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>cells_to_see_rec<CODE> </CODE><TT>(</TT>l2<CODE> </CODE><CODE>@</CODE><CODE> </CODE>t<TT>)</TT><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>visited<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><B>true</B><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>cells_to_see_rec<CODE> </CODE><CODE>[</CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE>]</CODE><CODE> </CODE><CODE> </CODE>;;<BR><CODE>val cells_to_see :</CODE><BR><CODE>  cell array array -&gt; config -&gt; int * int -&gt; (int * int) list = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
At first sight, the argument of <TT>cells_to_see_rec</TT> may grow
between two consecutive calls, although the recursion is based on this
argument. It is legitimate to wonder if this function always terminates.<BR>The way the <TT>visited</TT> array is used guarantees that a visited
cell cannot be in the result of the <TT>relevant</TT> function. Also,
all the cells to visit come from the result of the <TT>relevant</TT>
function. As the <TT>relevant</TT> function marks as visited all
the cells it returns, it returns each cell at most once, thus a cell
may be added to the list of cells to visit at most once. The number of
cells being finite, we deduce that the function terminates.<BR>
<BR>
Except for graphics, we are done with our Minesweeper. Let us take a look
at the programming style we have used. Mutable structures (arrays and
mutable record fields) make us use an imperative style of loops and
assignments. However, to deal with auxiliary issues, we use lists that
are processed by functions written in a functional style. Actually,
the programming style is a consequence of the data structure that it
manipulates. The function <TT>cells_to_see</TT> is a good example:
it processes lists, and it is natural to write it in a functional
style. Nevertheless, we use an array to remember the cells that were
already processed, and we update this array imperatively. We could use
a purely functional style by using a list of visited cells instead of an
array, and check if a cell is in the list to see if it was visited.
However, the cost of such a choice is important (looking up an element
in a list is linear in the size of the list, whereas accessing an
array element takes constant time) and it does not make the program
simpler.<BR>
<BR>
<A NAME="toc87"></A>
<H3> Displaying the Minesweeper game</H3>
<A NAME="demin-graph-jeu"></A>This part depends on the data structures representing the state of the
game (see page&nbsp;<A HREF="book-ora059.html#demin-data-types">??</A>). It consists of displaying
the different components of the Minesweeper window, as shown in
figure&nbsp;<A HREF="book-ora059.html#fig-demineur">6.6</A>. To this end, we use the box drawing
functions seen on page&nbsp;<A HREF="book-ora048.html#sec-boites">??</A>. <BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora025.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 6.6: <A NAME="fig-demineur"></A>The main window of Minesweeper.</DIV><BR>

<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>The following parameters characterize the components of the graphical
window.<BR>
<BR>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1>
<TR><TD  ALIGN=left NOWRAP>


<PRE><BR># <B>let</B><CODE> </CODE>b0<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>3</CODE><CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>w1<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>1</CODE><CODE>5</CODE><CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>w2<CODE> </CODE><CODE>=</CODE><CODE> </CODE>w1<CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>w4<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>2</CODE><CODE>0</CODE><CODE> </CODE><CODE>+</CODE><CODE> </CODE><CODE>2</CODE><CODE>*</CODE>b0<CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>w3<CODE> </CODE><CODE>=</CODE><CODE> </CODE>w4<CODE>*</CODE>default_config<CODE>.</CODE>nbcols<CODE> </CODE><CODE>+</CODE><CODE> </CODE><CODE>2</CODE><CODE>*</CODE>b0<CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>w5<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>4</CODE><CODE>0</CODE><CODE> </CODE><CODE>+</CODE><CODE> </CODE><CODE>2</CODE><CODE>*</CODE>b0<CODE> </CODE>;;<BR>

</PRE>

&nbsp;
</TD>
<TD  ALIGN=left NOWRAP>


<PRE><BR># <B>let</B><CODE> </CODE>h1<CODE> </CODE><CODE>=</CODE><CODE> </CODE>w1<CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>h2<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>3</CODE><CODE>0</CODE><CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>h3<CODE> </CODE><CODE>=</CODE><CODE> </CODE>w5<CODE>+</CODE><CODE>2</CODE><CODE>0</CODE><CODE> </CODE><CODE>+</CODE><CODE> </CODE><CODE>2</CODE><CODE>*</CODE>b0<CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>h4<CODE> </CODE><CODE>=</CODE><CODE> </CODE>h2<CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>h5<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>2</CODE><CODE>0</CODE><CODE> </CODE><CODE>+</CODE><CODE> </CODE><CODE>2</CODE><CODE>*</CODE>b0<CODE> </CODE>;;<BR># <B>let</B><CODE> </CODE>h6<CODE> </CODE><CODE>=</CODE><CODE> </CODE>w5<CODE> </CODE><CODE>+</CODE><CODE> </CODE><CODE>2</CODE><CODE>*</CODE>b0<CODE> </CODE>;;<BR>

</PRE>

&nbsp;</TD>
</TR></TABLE><BR>
We use them to extend the basic configuration of our Minesweeper board
(value of type <I>config</I>). Below, we define a record type
<I>window_config</I>. The <TT>cf</TT> field contains the basic
configuration. We associate a box with every component of the display:
main window (field <TT>main_box</TT>), mine field (field
<TT>field_box</TT>), dialog window (field <TT>dialog_box</TT>) with two
sub-boxes (fields <TT>d1_box</TT> and <TT>d2_box</TT>), flagging
button (field <TT>flag_box</TT>) and current cell (field
 <TT>current_box</TT>).


<PRE><BR># <B>type</B><CODE> </CODE>window_config<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>cf<CODE> </CODE><CODE>:</CODE><CODE> </CODE>config<CODE> </CODE>;<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>main_box<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>;<CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>field_box<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>dialog_box<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>d1_box<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>d2_box<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>flag_box<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>current_box<CODE> </CODE><CODE>:</CODE><CODE> </CODE>box_config<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>cell<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE>*</CODE>int<CODE> </CODE>-&gt;<CODE> </CODE><TT>(</TT>int<CODE>*</CODE>int<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>coor<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE>*</CODE>int<CODE> </CODE>-&gt;<CODE> </CODE><TT>(</TT>int<CODE>*</CODE>int<TT>)</TT><CODE> </CODE><BR><CODE> </CODE>}<CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
Moreover, a record of type <I>window_config</I> contains two functions:
<UL>
<LI>
 <TT>cell</TT>: takes the coordinates of a cell and returns the
 coordinates of the corresponding box;

<LI> <TT>coor</TT>: takes the coordinates of a pixel of the window
 and returns the coordinates of the corresponding cell.
</UL>
<H5> Configuration</H5>
We now define a function that builds a graphical configuration (of type
<I>window_config</I>) according to a basic configuration (of type
<I>config</I>) and the parameters above. The values of the
parameters of some components depend on the value of the parameters of
other components. For instance, the global box width depends on the
mine field width, which, in turn, depends on the number of columns. To avoid
computing the same value several times, we incrementally create the
components. This initialization phase of a graphical configuration is
always a little tedious when there is no adequate primitive or
tool available.


<PRE><BR># <B>let</B><CODE> </CODE>make_box<CODE> </CODE>x<CODE> </CODE>y<CODE> </CODE>w<CODE> </CODE>h<CODE> </CODE>bw<CODE> </CODE>r<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>{<CODE> </CODE>x<CODE>=</CODE>x;<CODE> </CODE>y<CODE>=</CODE>y;<CODE> </CODE>w<CODE>=</CODE>w;<CODE> </CODE>h<CODE>=</CODE>h;<CODE> </CODE>bw<CODE>=</CODE>bw;<CODE> </CODE>r<CODE>=</CODE>r;<CODE> </CODE>b1_col<CODE>=</CODE>gray1;<CODE> </CODE>b2_col<CODE>=</CODE>gray3;<CODE> </CODE>b_col<CODE>=</CODE>gray2<CODE> </CODE>}<CODE> </CODE>;;<BR><CODE>val make_box : int -&gt; int -&gt; int -&gt; int -&gt; int -&gt; relief -&gt; box_config =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>make_wcf<CODE> </CODE>cf<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>wcols<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE>b0<CODE> </CODE><CODE>+</CODE><CODE> </CODE>cf<CODE>.</CODE>nbcols<CODE>*</CODE>w4<CODE> </CODE><CODE>+</CODE><CODE> </CODE>b0<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>hrows<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE>b0<CODE> </CODE><CODE>+</CODE><CODE> </CODE>cf<CODE>.</CODE>nbrows<CODE>*</CODE>h5<CODE> </CODE><CODE>+</CODE><CODE> </CODE>b0<CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>main_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>gw<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>b0<CODE> </CODE><CODE>+</CODE><CODE> </CODE>w1<CODE> </CODE><CODE>+</CODE><CODE> </CODE>wcols<CODE> </CODE><CODE>+</CODE><CODE> </CODE>w2<CODE> </CODE><CODE>+</CODE><CODE> </CODE>b0<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>gh<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>b0<CODE> </CODE><CODE>+</CODE><CODE> </CODE>h1<CODE> </CODE><CODE>+</CODE><CODE> </CODE>hrows<CODE> </CODE><CODE>+</CODE><CODE> </CODE>h2<CODE> </CODE><CODE>+</CODE><CODE> </CODE>h3<CODE> </CODE><CODE>+</CODE><CODE> </CODE>h4<CODE> </CODE><CODE>+</CODE><CODE> </CODE>b0<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>make_box<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>gw<CODE> </CODE>gh<CODE> </CODE>b0<CODE> </CODE>Top<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>field_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>make_box<CODE> </CODE>w1<CODE> </CODE>h1<CODE> </CODE>wcols<CODE> </CODE>hrows<CODE> </CODE>b0<CODE> </CODE>Bot<CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>dialog_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>make_box<CODE> </CODE><CODE> </CODE><TT>(</TT><TT>(</TT>main_box<CODE>.</CODE>w<CODE> </CODE><CODE>-</CODE><CODE> </CODE>w3<TT>)</TT><CODE> </CODE><CODE>/</CODE><CODE> </CODE><CODE>2</CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>b0<CODE>+</CODE>h1<CODE>+</CODE>hrows<CODE>+</CODE>h2<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>w3<CODE> </CODE>h3<CODE> </CODE>b0<CODE> </CODE>Bot<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>d1_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>make_box<CODE> </CODE><TT>(</TT>dialog_box<CODE>.</CODE>x<CODE> </CODE><CODE>+</CODE><CODE> </CODE>b0<TT>)</TT><CODE> </CODE><TT>(</TT>b0<CODE> </CODE><CODE>+</CODE><CODE> </CODE>h1<CODE> </CODE><CODE>+</CODE><CODE> </CODE>hrows<CODE> </CODE><CODE>+</CODE><CODE> </CODE>h2<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><TT>(</TT>w3<CODE>-</CODE>w5<TT>)</TT><CODE>/</CODE><CODE>2</CODE><CODE>-</CODE><TT>(</TT><CODE>2</CODE><CODE>*</CODE>b0<TT>)</TT><TT>)</TT><CODE> </CODE><TT>(</TT>h3<CODE>-</CODE><TT>(</TT><CODE>2</CODE><CODE>*</CODE>b0<TT>)</TT><TT>)</TT><CODE> </CODE><CODE>5</CODE><CODE> </CODE>Flat<CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>flag_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>make_box<CODE> </CODE><TT>(</TT>d1_box<CODE>.</CODE>x<CODE> </CODE><CODE>+</CODE><CODE> </CODE>d1_box<CODE>.</CODE>w<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>d1_box<CODE>.</CODE>y<CODE> </CODE><CODE>+</CODE><CODE> </CODE><TT>(</TT>h3<CODE>-</CODE>h6<TT>)</TT><CODE> </CODE><CODE>/</CODE><CODE> </CODE><CODE>2</CODE><TT>)</TT><CODE> </CODE>w5<CODE> </CODE>h6<CODE> </CODE>b0<CODE> </CODE>Top<CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>d2_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>make_box<CODE> </CODE><TT>(</TT>flag_box<CODE>.</CODE>x<CODE> </CODE><CODE>+</CODE><CODE> </CODE>flag_box<CODE>.</CODE>w<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>d1_box<CODE>.</CODE>y<CODE> </CODE>d1_box<CODE>.</CODE>w<CODE> </CODE>d1_box<CODE>.</CODE>h<CODE> </CODE><CODE>5</CODE><CODE> </CODE>Flat<CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>current_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>make_box<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>w4<CODE> </CODE>h5<CODE> </CODE>b0<CODE> </CODE>Top<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>{<CODE> </CODE>cf<CODE> </CODE><CODE>=</CODE><CODE> </CODE>cf;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>main_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>main_box;<CODE> </CODE>field_box<CODE>=</CODE>field_box;<CODE> </CODE>dialog_box<CODE>=</CODE>dialog_box;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>d1_box<CODE>=</CODE>d1_box;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flag_box<CODE>=</CODE>flag_box;<CODE> </CODE>d2_box<CODE>=</CODE>d2_box;<CODE> </CODE>current_box<CODE> </CODE><CODE>=</CODE><CODE> </CODE>current_box;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>cell<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE><TT>(</TT><CODE> </CODE>w1<CODE>+</CODE>b0<CODE>+</CODE>w4<CODE>*</CODE>i<CODE> </CODE><CODE>,</CODE><CODE> </CODE>h1<CODE>+</CODE>b0<CODE>+</CODE>h5<CODE>*</CODE>j<TT>)</TT><TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>coor<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE><TT>(</TT><CODE> </CODE><TT>(</TT>x<CODE>-</CODE>w1<TT>)</TT><CODE>/</CODE>w4<CODE> </CODE><CODE>,</CODE><CODE> </CODE><TT>(</TT>y<CODE>-</CODE>h1<TT>)</TT><CODE>/</CODE>h5<CODE> </CODE><TT>)</TT><TT>)</TT><CODE> </CODE>}<CODE> </CODE>;;<BR><CODE>val make_wcf : config -&gt; window_config = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Cell display</H5>
We now need to write the functions to display the cells in their
different states. A cell may be open or closed and may contain some
information. We always display (the box corresponding with) the current
cell in the game configuration (field <TT>cc_bcf</TT>).<BR>
<BR>
We thus write two functions modifying the configuration of the current
cell; one closing it, the other opening it.


<PRE><BR># <B>let</B><CODE> </CODE>close_ccell<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>x<CODE>,</CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>cell<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>{wcf<CODE>.</CODE>current_box<CODE> </CODE><B>with</B><CODE> </CODE>x<CODE>=</CODE>x;<CODE> </CODE>y<CODE>=</CODE>y;<CODE> </CODE>r<CODE>=</CODE>Top}<CODE> </CODE>;;<BR><CODE>val close_ccell : window_config -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR># <B>let</B><CODE> </CODE>open_ccell<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>x<CODE>,</CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>cell<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>{wcf<CODE>.</CODE>current_box<CODE> </CODE><B>with</B><CODE> </CODE>x<CODE>=</CODE>x;<CODE> </CODE>y<CODE>=</CODE>y;<CODE> </CODE>r<CODE>=</CODE>Flat}<CODE> </CODE>;;<CODE> </CODE><BR><CODE>val open_ccell : window_config -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Depending on the game phase, we may need to display some information
on the cells. We write, for each case, a specialized function.
<UL>
<LI>
 Display of a closed cell:


<PRE><BR># <B>let</B><CODE> </CODE>draw_closed_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE>close_ccell<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j;<BR><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE>;;<BR><CODE>val draw_closed_cc : window_config -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<LI> Display of an opened cell with its number of neighbor mines:


<PRE><BR># <B>let</B><CODE> </CODE>draw_num_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>open_ccell<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>n<CODE>&lt;&gt;</CODE><CODE>0</CODE><CODE> </CODE><B>then</B><CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE>n<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE>Graphics.white<CODE> </CODE>;;<BR><CODE>val draw_num_cc : window_config -&gt; int -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<LI> Display of a cell containing a mine:


<PRE><BR># <B>let</B><CODE> </CODE>draw_mine_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>open_ccell<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cc<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.set_color<CODE> </CODE>Graphics.black<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.fill_circle<CODE> </CODE><TT>(</TT>cc<CODE>.</CODE>x<CODE>+</CODE>cc<CODE>.</CODE>w<CODE>/</CODE><CODE>2</CODE><TT>)</TT><CODE> </CODE><TT>(</TT>cc<CODE>.</CODE>y<CODE>+</CODE>cc<CODE>.</CODE>h<CODE>/</CODE><CODE>2</CODE><TT>)</TT><CODE> </CODE><TT>(</TT>cc<CODE>.</CODE>h<CODE>/</CODE><CODE>3</CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>val draw_mine_cc : window_config -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<LI> Display of a flagged cell containing a mine:


<PRE><BR># <B>let</B><CODE> </CODE>draw_flag_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>close_ccell<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE><CODE>"!"</CODE><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE>Graphics.blue<CODE> </CODE>;;<BR><CODE>val draw_flag_cc : window_config -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<LI> Display of a wrongly flagged cell:


<PRE><BR># <B>let</B><CODE> </CODE>draw_cross_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>x<CODE>,</CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>cell<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>w<CODE>,</CODE>h<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE>.</CODE>w<CODE>,</CODE><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE>.</CODE>h<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>a<CODE>=</CODE>x<CODE>+</CODE>w<CODE>/</CODE><CODE>4</CODE><CODE> </CODE><B>and</B><CODE> </CODE>b<CODE>=</CODE>x<CODE>+</CODE><CODE>3</CODE><CODE>*</CODE>w<CODE>/</CODE><CODE>4</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>c<CODE>=</CODE>y<CODE>+</CODE>h<CODE>/</CODE><CODE>4</CODE><CODE> </CODE><B>and</B><CODE> </CODE>d<CODE>=</CODE>y<CODE>+</CODE><CODE>3</CODE><CODE>*</CODE>h<CODE>/</CODE><CODE>4</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Graphics.set_color<CODE> </CODE>Graphics.red<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.set_line_width<CODE> </CODE><CODE>3</CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.moveto<CODE> </CODE>a<CODE> </CODE>d<CODE> </CODE>;<CODE> </CODE>Graphics.lineto<CODE> </CODE>b<CODE> </CODE>c<CODE> </CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.moveto<CODE> </CODE>a<CODE> </CODE>c<CODE> </CODE>;<CODE> </CODE>Graphics.lineto<CODE> </CODE>b<CODE> </CODE>d<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.set_line_width<CODE> </CODE><CODE>1</CODE><CODE> </CODE>;;<BR><CODE>val draw_cross_cc : window_config -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
</UL>During the game, the choice of the display function to use is done by:


<PRE><BR># <B>let</B><CODE> </CODE>draw_cell<CODE> </CODE>wcf<CODE> </CODE>bd<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cell<CODE> </CODE><CODE>=</CODE><CODE> </CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>match</B><CODE> </CODE><TT>(</TT>cell<CODE>.</CODE>flag<CODE>,</CODE><CODE> </CODE>cell<CODE>.</CODE>seen<CODE> </CODE><CODE>,</CODE><CODE> </CODE>cell<CODE>.</CODE>mined<CODE> </CODE><TT>)</TT><CODE> </CODE><B>with</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>true</B><CODE>,_,_</CODE><TT>)</TT><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE>draw_flag_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><TT>(</TT><CODE>_,</CODE><B>false</B><CODE>,_</CODE><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_closed_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><TT>(</TT><CODE>_,_,</CODE><B>true</B><TT>)</TT><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE>draw_mine_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE>draw_num_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE>cell<CODE>.</CODE>nbm<CODE> </CODE><CODE> </CODE>;;<BR><CODE>val draw_cell : window_config -&gt; cell array array -&gt; int -&gt; int -&gt; unit =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
A specialized function displays all the cells at the end of the game.
It is slightly different from the previous one as all the cells are
taken as opened. Moreover, a red cross indicates the empty cells where
the player wrongly put a flag.


<PRE><BR># <B>let</B><CODE> </CODE>draw_cell_end<CODE> </CODE>wcf<CODE> </CODE>bd<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cell<CODE> </CODE><CODE>=</CODE><CODE> </CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>match</B><CODE> </CODE><TT>(</TT>cell<CODE>.</CODE>flag<CODE>,</CODE><CODE> </CODE>cell<CODE>.</CODE>mined<CODE> </CODE><TT>)</TT><CODE> </CODE><B>with</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>true</B><CODE>,</CODE><B>true</B><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_flag_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><TT>(</TT><B>true</B><CODE>,</CODE><B>false</B><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_num_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE>cell<CODE>.</CODE>nbm;<CODE> </CODE>draw_cross_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><TT>(</TT><B>false</B><CODE>,</CODE><B>true</B><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_mine_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><TT>(</TT><B>false</B><CODE>,</CODE><B>false</B><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_num_cc<CODE> </CODE>wcf<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE>cell<CODE>.</CODE>nbm<CODE> </CODE>;;<BR><CODE>val draw_cell_end : window_config -&gt; cell array array -&gt; int -&gt; int -&gt; unit =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Display of the other components</H5>
The state of the flagging mode is indicated by a box that is either at
the bottom or on top and that contain either the word <TT>ON</TT> or <TT>OFF</TT>:


<PRE><BR># <B>let</B><CODE> </CODE>draw_flag_switch<CODE> </CODE>wcf<CODE> </CODE>on<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>on<CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>r<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>Bot<CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>r<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>Top<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>flag_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>on<CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE><CODE>"ON"</CODE><CODE> </CODE>wcf<CODE>.</CODE>flag_box<CODE> </CODE>Graphics.red<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE><CODE>"OFF"</CODE><CODE> </CODE>wcf<CODE>.</CODE>flag_box<CODE> </CODE>Graphics.blue<CODE> </CODE>;;<BR><CODE>val draw_flag_switch : window_config -&gt; bool -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
We display the purpose of the flagging button above it:


<PRE><BR># <B>let</B><CODE> </CODE>draw_flag_title<CODE> </CODE>wcf<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>m<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"Flagging"</CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>w<CODE>,</CODE>h<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Graphics.text_size<CODE> </CODE>m<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>wcf<CODE>.</CODE>main_box<CODE>.</CODE>w<CODE>-</CODE>w<TT>)</TT><CODE>/</CODE><CODE>2</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>y0<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>dialog_box<CODE>.</CODE>y<CODE>+</CODE>wcf<CODE>.</CODE>dialog_box<CODE>.</CODE>h<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y0<CODE>+</CODE><TT>(</TT>wcf<CODE>.</CODE>main_box<CODE>.</CODE>h<CODE>-</CODE><TT>(</TT>y0<CODE>+</CODE>h<TT>)</TT><TT>)</TT><CODE>/</CODE><CODE>2</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Graphics.moveto<CODE> </CODE>x<CODE> </CODE>y<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.draw_string<CODE> </CODE>m<CODE> </CODE>;;<CODE> </CODE><BR><CODE>val draw_flag_title : window_config -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
During the game, the number of empty cells left to be opened and the number
of cells to flag are displayed in the dialog box, to the left and 
right of the flagging mode button.


<PRE><BR># <B>let</B><CODE> </CODE>print_score<CODE> </CODE>wcf<CODE> </CODE>nbcto<CODE> </CODE>nbfc<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>erase_box<CODE> </CODE>wcf<CODE>.</CODE>d1_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE>nbcto<TT>)</TT><CODE> </CODE>wcf<CODE>.</CODE>d1_box<CODE> </CODE>Graphics.blue<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>erase_box<CODE> </CODE>wcf<CODE>.</CODE>d2_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE><TT>(</TT>wcf<CODE>.</CODE>cf<CODE>.</CODE>nbmines<CODE>-</CODE>nbfc<TT>)</TT><TT>)</TT><CODE> </CODE>wcf<CODE>.</CODE>d2_box<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><CODE> </CODE><B>if</B><CODE> </CODE>nbfc<CODE>&gt;</CODE>wcf<CODE>.</CODE>cf<CODE>.</CODE>nbmines<CODE> </CODE><B>then</B><CODE> </CODE>Graphics.red<CODE> </CODE><B>else</B><CODE> </CODE>Graphics.blue<CODE> </CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>val print_score : window_config -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
To draw the initial mine field, we need to draw (number of rows)
� (number of columns) times the same closed cell. It is always
the same drawing, but it may take a long time, as it is necessary to
draw a rectangle as well as four trapezoids. To speed up this
initialization, we draw only one cell, take the bitmap corresponding
to this drawing, and paste this bitmap into every cell.


<PRE><BR># <B>let</B><CODE> </CODE>draw_field_initial<CODE> </CODE>wcf<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_closed_cc<CODE> </CODE>wcf<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cc<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>current_box<CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>bitmap<CODE> </CODE><CODE>=</CODE><CODE> </CODE>draw_box<CODE> </CODE>cc<CODE> </CODE>;<CODE> </CODE>Graphics.get_image<CODE> </CODE>cc<CODE>.</CODE>x<CODE> </CODE>cc<CODE>.</CODE>y<CODE> </CODE>cc<CODE>.</CODE>w<CODE> </CODE>cc<CODE>.</CODE>h<CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>draw_bitmap<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>let</B><CODE> </CODE>x<CODE>,</CODE>y<CODE>=</CODE>wcf<CODE>.</CODE>cell<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Graphics.draw_image<CODE> </CODE>bitmap<CODE> </CODE>x<CODE> </CODE>y<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>iter_cells<CODE> </CODE>wcf<CODE>.</CODE>cf<CODE> </CODE>draw_bitmap<CODE> </CODE><CODE> </CODE>;;<BR><CODE>val draw_field_initial : window_config -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
At the end of the game, we open the whole mine field while putting
a red cross on cells wrongly flagged:


<PRE><BR># <B>let</B><CODE> </CODE>draw_field_end<CODE> </CODE>wcf<CODE> </CODE>bd<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>iter_cells<CODE> </CODE>wcf<CODE>.</CODE>cf<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>draw_cell_end<CODE> </CODE>wcf<CODE> </CODE>bd<CODE> </CODE>i<CODE> </CODE>j<TT>)</TT><CODE> </CODE><CODE> </CODE>;;<BR><CODE>val draw_field_end : window_config -&gt; cell array array -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Finally, the main display function called at the beginning of the game
opens the graphical context and displays the initial state of all the
components.


<PRE><BR># <B>let</B><CODE> </CODE>open_wcf<CODE> </CODE>wcf<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>Graphics.open_graph<CODE> </CODE><TT>(</TT><CODE> </CODE><CODE>" "</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE>wcf<CODE>.</CODE>main_box<CODE>.</CODE>w<TT>)</TT><CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>"x"</CODE><CODE> </CODE><CODE>^</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>string_of_int<CODE> </CODE>wcf<CODE>.</CODE>main_box<CODE>.</CODE>h<TT>)</TT><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>main_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>dialog_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_flag_switch<CODE> </CODE>wcf<CODE> </CODE><B>false</B><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_box<CODE> </CODE>wcf<CODE>.</CODE>field_box<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_field_initial<CODE> </CODE>wcf<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_flag_title<CODE> </CODE>wcf<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_score<CODE> </CODE>wcf<CODE> </CODE><TT>(</TT><TT>(</TT>wcf<CODE>.</CODE>cf<CODE>.</CODE>nbrows<CODE>*</CODE>wcf<CODE>.</CODE>cf<CODE>.</CODE>nbcols<TT>)</TT><CODE>-</CODE>wcf<CODE>.</CODE>cf<CODE>.</CODE>nbmines<TT>)</TT><CODE> </CODE><CODE>0</CODE><CODE> </CODE>;;<BR><CODE>val open_wcf : window_config -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Notice that all the display primitives are parameterized by a
graphical configuration of type <I>window_config</I>. This makes
them independent of the layout of the components of our Minesweeper. If we
wish to modify the layout, the code still works without any
modification, only the configuration needs to be updated.<BR>
<BR>
<A NAME="toc88"></A>
<H3> Interaction with the player</H3>We now list what the player may do:<BR>
<BR>
<UL>
<LI>
 he may click on the mode box to change mode (opening or flagging),

<LI> he may click on a cell to open it or flag it,

<LI> he may hit the <CODE>'q'</CODE> key to quit the game.
</UL>
Recall that a <TT>Graphic</TT> event (<I>Graphics.event</I>)
must be associated with a record (<I>Graphics.status</I>) that
contains the current information on the mouse and keyboard when the
event occurs. An interaction with the mouse may happen on the mode
button, or on a cell of the mine field. Every other mouse event must
be ignored. In order to differentiate these mouse events, we create
the type:


<PRE><BR># <B>type</B><CODE> </CODE>clickon<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Out<CODE> </CODE><CODE>|</CODE><CODE> </CODE>Cell<CODE> </CODE><B>of</B><CODE> </CODE><TT>(</TT>int<CODE>*</CODE>int<TT>)</TT><CODE> </CODE><CODE>|</CODE><CODE> </CODE>SelectBox<CODE> </CODE><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
Also, pressing the mouse button and releasing it are two different
events. For a click to be valid, we require that both events occur on
the same component (the flagging mode button or a cell of the mine
field).


<PRE><BR># <B>let</B><CODE> </CODE>locate_click<CODE> </CODE>wcf<CODE> </CODE>st1<CODE> </CODE>st2<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>clickon_of<CODE> </CODE>st<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>st<CODE>.</CODE>Graphics.mouse_x<CODE> </CODE><B>and</B><CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>st<CODE>.</CODE>Graphics.mouse_y<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>if</B><CODE> </CODE>x<CODE>&gt;=</CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>x<CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>x<CODE>&lt;=</CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>x<CODE>+</CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>w<CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>y<CODE>&gt;=</CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>y<CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>y<CODE>&lt;=</CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>y<CODE>+</CODE>wcf<CODE>.</CODE>flag_box<CODE>.</CODE>h<CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE>SelectBox<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><B>let</B><CODE> </CODE><TT>(</TT>x2<CODE>,</CODE>y2<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE>.</CODE>coor<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>if</B><CODE> </CODE>x2<CODE>&gt;=</CODE><CODE>0</CODE><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>x2<CODE>&lt;</CODE>wcf<CODE>.</CODE>cf<CODE>.</CODE>nbcols<CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>y2<CODE>&gt;=</CODE><CODE>0</CODE><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE>y2<CODE>&lt;</CODE>wcf<CODE>.</CODE>cf<CODE>.</CODE>nbrows<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE>Cell<CODE> </CODE><TT>(</TT>x2<CODE>,</CODE>y2<TT>)</TT><CODE> </CODE><B>else</B><CODE> </CODE>Out<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>r1<CODE>=</CODE>clickon_of<CODE> </CODE>st1<CODE> </CODE><B>and</B><CODE> </CODE>r2<CODE>=</CODE>clickon_of<CODE> </CODE>st2<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>if</B><CODE> </CODE>r1<CODE>=</CODE>r2<CODE> </CODE><B>then</B><CODE> </CODE>r1<CODE> </CODE><B>else</B><CODE> </CODE>Out<CODE> </CODE>;;<BR><CODE>val locate_click :</CODE><BR><CODE>  window_config -&gt; Graphics.status -&gt; Graphics.status -&gt; clickon = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The heart of the program is the event waiting and processing loop
defined in the function <TT>loop</TT>. It is similar to the function
<TT>skel</TT> described page&nbsp;<A HREF="book-ora050.html#sec-squelette">??</A>, but specifies
the mouse events more precisely. The loop ends when:
<UL>
<LI>
 the player presses the <TT>q</TT> or <TT>Q</TT> key, meaning that he
 wants to end the game;

<LI> the player opens a cell containing a mine, then he loses;

<LI> the player has opened all the cell that are empty, then he wins
 the game.
</UL> We gather in a record of type <I>minesw_cf</I> the information
useful for the interface:


<PRE><BR># <B>type</B><CODE> </CODE>minesw_cf<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>{<CODE> </CODE>wcf<CODE> </CODE><CODE>:</CODE><CODE> </CODE>window_config;<CODE> </CODE>bd<CODE> </CODE><CODE>:</CODE><CODE> </CODE>cell<CODE> </CODE>array<CODE> </CODE>array;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>nb_flagged_cells<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>nb_hidden_cells<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int;<CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>mutable</B><CODE> </CODE>flag_switch_on<CODE> </CODE><CODE>:</CODE><CODE> </CODE>bool<CODE> </CODE>}<CODE> </CODE>;;<BR>

</PRE>

The meaning of the fields is:
<UL>
<LI>
 <TT>wcf</TT>: the graphical configuration;

<LI> <TT>bd</TT>: the board;

<LI> <TT>flag_switch_on</TT>: a boolean indicating whether flagging
 mode or opening mode is on;

<LI> <TT>nb_flagged_cells</TT>: the number of flagged cells;

<LI> <TT>nb_hidden_cells</TT>: the number of empty cells left to open;
</UL>The main loop is implemented this way:


<PRE><BR># <B>let</B><CODE> </CODE>loop<CODE> </CODE>d<CODE> </CODE>f_init<CODE> </CODE>f_key<CODE> </CODE>f_mouse<CODE> </CODE>f_end<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>f_init<CODE> </CODE>();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>st<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Graphics.wait_next_event<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>[</CODE>Graphics<CODE>.</CODE>Button_down;Graphics<CODE>.</CODE>Key_pressed<CODE>]</CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><B>if</B><CODE> </CODE>st<CODE>.</CODE>Graphics.keypressed<CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE>f_key<CODE> </CODE>st<CODE>.</CODE>Graphics.key<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><B>let</B><CODE> </CODE>st2<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Graphics.wait_next_event<CODE> </CODE><CODE>[</CODE>Graphics<CODE>.</CODE>Button_up<CODE>]</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>f_mouse<CODE> </CODE><TT>(</TT>locate_click<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE>st<CODE> </CODE>st2<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>End<CODE> </CODE>-&gt;<CODE> </CODE>f_end<CODE> </CODE>();;<BR><CODE>val loop :</CODE><BR><CODE>  minesw_cf -&gt;</CODE><BR><CODE>  (unit -&gt; 'a) -&gt; (char -&gt; 'b) -&gt; (clickon -&gt; 'b) -&gt; (unit -&gt; unit) -&gt; unit =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The initialization function, cleanup function and keyboard event
processing function are very simple.


<PRE><BR># <B>let</B><CODE> </CODE>d_init<CODE> </CODE>d<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>open_wcf<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><B>let</B><CODE> </CODE>d_end<CODE> </CODE><CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Graphics.close_graph()<BR><CODE> </CODE><B>let</B><CODE> </CODE>d_key<CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>if</B><CODE> </CODE>c<CODE>=</CODE><CODE>'q'</CODE><CODE> </CODE><CODE>||</CODE><CODE> </CODE>c<CODE>=</CODE><CODE>'Q'</CODE><CODE> </CODE><B>then</B><CODE> </CODE>raise<CODE> </CODE>End;;<BR><CODE>val d_init : minesw_cf -&gt; unit -&gt; unit = &lt;fun&gt;</CODE><BR><CODE>val d_end : unit -&gt; unit = &lt;fun&gt;</CODE><BR><CODE>val d_key : char -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
However, the mouse event processing function requires the use of some
auxiliary functions:
<UL>
<LI>
 <TT>flag_cell</TT>: when clicking on a cell with flagging
 mode on.

<LI> <TT>ending</TT>: when ending the game. The whole mine field is
 revealed, we display a message indicating whether the game was won or lost,
 and we wait for a mouse or keyboard event to quit the application.

<LI> <TT>reveal</TT>: when clicking on a cell with opening mode
 on (i.e. flagging mode off).
</UL>


<PRE><BR># <B>let</B><CODE> </CODE>flag_cell<CODE> </CODE>d<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>d<CODE>.</CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>flag<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>then</B><CODE> </CODE><TT>(</TT><CODE> </CODE>d<CODE>.</CODE>nb_flagged_cells<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>d<CODE>.</CODE>nb_flagged_cells<CODE> </CODE><CODE>-</CODE><CODE>1</CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>d<CODE>.</CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>flag<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><B>false</B><CODE> </CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><TT>(</TT><CODE> </CODE>d<CODE>.</CODE>nb_flagged_cells<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>d<CODE>.</CODE>nb_flagged_cells<CODE> </CODE><CODE>+</CODE><CODE>1</CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>d<CODE>.</CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>flag<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><B>true</B><CODE> </CODE><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_cell<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE>d<CODE>.</CODE>bd<CODE> </CODE>i<CODE> </CODE>j;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_score<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE>d<CODE>.</CODE>nb_hidden_cells<CODE> </CODE>d<CODE>.</CODE>nb_flagged_cells;;<BR><CODE>val flag_cell : minesw_cf -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>ending<CODE> </CODE>d<CODE> </CODE>str<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_field_end<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE>d<CODE>.</CODE>bd;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>erase_box<CODE> </CODE><CODE> </CODE>d<CODE>.</CODE>wcf<CODE>.</CODE>flag_box;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_string_in_box<CODE> </CODE>Center<CODE> </CODE>str<CODE> </CODE>d<CODE>.</CODE>wcf<CODE>.</CODE>flag_box<CODE> </CODE>Graphics.black;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>ignore<TT>(</TT>Graphics.wait_next_event<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>[</CODE>Graphics<CODE>.</CODE>Button_down;Graphics<CODE>.</CODE>Key_pressed<CODE>]</CODE><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>raise<CODE> </CODE>End;;<BR><CODE>val ending : minesw_cf -&gt; string -&gt; 'a = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>reveal<CODE> </CODE>d<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>reveal_cell<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>d<CODE>.</CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>seen<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><B>true</B>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_cell<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE>d<CODE>.</CODE>bd<CODE> </CODE>i<CODE> </CODE>j;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>d<CODE>.</CODE>nb_hidden_cells<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>d<CODE>.</CODE>nb_hidden_cells<CODE> </CODE><CODE>-</CODE><CODE>1</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.iter<CODE> </CODE>reveal_cell<CODE> </CODE><TT>(</TT>cells_to_see<CODE> </CODE>d<CODE>.</CODE>bd<CODE> </CODE>d<CODE>.</CODE>wcf<CODE>.</CODE>cf<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_score<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE>d<CODE>.</CODE>nb_hidden_cells<CODE> </CODE>d<CODE>.</CODE>nb_flagged_cells;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>d<CODE>.</CODE>nb_hidden_cells<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE><B>then</B><CODE> </CODE>ending<CODE> </CODE>d<CODE> </CODE><CODE>"WON"</CODE>;;<BR><CODE>val reveal : minesw_cf -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The mouse event processing function matches a value of type <I>clickon</I>.


<PRE><BR># <B>let</B><CODE> </CODE>d_mouse<CODE> </CODE>d<CODE> </CODE>click<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>match</B><CODE> </CODE>click<CODE> </CODE><B>with</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Cell<CODE> </CODE><TT>(</TT>i<CODE>,</CODE>j<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>d<CODE>.</CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>seen<CODE> </CODE><B>then</B><CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><B>if</B><CODE> </CODE>d<CODE>.</CODE>flag_switch_on<CODE> </CODE><B>then</B><CODE> </CODE>flag_cell<CODE> </CODE>d<CODE> </CODE>i<CODE> </CODE>j<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><B>if</B><CODE> </CODE>d<CODE>.</CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>flag<CODE> </CODE><B>then</B><CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><B>if</B><CODE> </CODE>d<CODE>.</CODE>bd<CODE>.</CODE><TT>(</TT>i<TT>)</TT><CODE>.</CODE><TT>(</TT>j<TT>)</TT><CODE>.</CODE>mined<CODE> </CODE><B>then</B><CODE> </CODE>ending<CODE> </CODE>d<CODE> </CODE><CODE>"LOST"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE>reveal<CODE> </CODE>d<CODE> </CODE>i<CODE> </CODE>j<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE>SelectBox<CODE> </CODE>-&gt;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>d<CODE>.</CODE>flag_switch_on<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>not<CODE> </CODE>d<CODE>.</CODE>flag_switch_on;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>draw_flag_switch<CODE> </CODE>d<CODE>.</CODE>wcf<CODE> </CODE>d<CODE>.</CODE>flag_switch_on<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE>Out<CODE> </CODE>-&gt;<CODE> </CODE>()<CODE> </CODE>;;<BR><CODE>val d_mouse : minesw_cf -&gt; clickon -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
To create a game configuration, three parameters are needed: the
number of columns, the number of rows, and the number of mines.


<PRE><BR># <B>let</B><CODE> </CODE>create_minesw<CODE> </CODE>nb_c<CODE> </CODE>nb_r<CODE> </CODE>nb_m<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>nbc<CODE> </CODE><CODE>=</CODE><CODE> </CODE>max<CODE> </CODE>default_config<CODE>.</CODE>nbcols<CODE> </CODE>nb_c<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>nbr<CODE> </CODE><CODE>=</CODE><CODE> </CODE>max<CODE> </CODE>default_config<CODE>.</CODE>nbrows<CODE> </CODE>nb_r<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>nbm<CODE> </CODE><CODE>=</CODE><CODE> </CODE>min<CODE> </CODE><TT>(</TT>nbc<CODE>*</CODE>nbr<TT>)</TT><CODE> </CODE><TT>(</TT>max<CODE> </CODE><CODE>1</CODE><CODE> </CODE>nb_m<TT>)</TT><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>cf<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>nbcols<CODE>=</CODE>nbc<CODE> </CODE>;<CODE> </CODE>nbrows<CODE>=</CODE>nbr<CODE> </CODE>;<CODE> </CODE>nbmines<CODE>=</CODE>nbm<CODE> </CODE>}<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>generate_seed<CODE> </CODE>()<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>wcf<CODE> </CODE><CODE>=</CODE><CODE> </CODE>make_wcf<CODE> </CODE>cf<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>{<CODE> </CODE><CODE> </CODE>wcf<CODE> </CODE><CODE>=</CODE><CODE> </CODE>wcf<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>bd<CODE> </CODE><CODE>=</CODE><CODE> </CODE>initialize_board<CODE> </CODE>wcf<CODE>.</CODE>cf;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>nb_flagged_cells<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>0</CODE>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>nb_hidden_cells<CODE> </CODE><CODE>=</CODE><CODE> </CODE>cf<CODE>.</CODE>nbrows<CODE>*</CODE>cf<CODE>.</CODE>nbcols<CODE>-</CODE>cf<CODE>.</CODE>nbmines;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flag_switch_on<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>false</B><CODE> </CODE>}<CODE> </CODE>;;<BR><CODE>val create_minesw : int -&gt; int -&gt; int -&gt; minesw_cf = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The launch function creates a configuration according to the numbers
of columns, rows, and mines, before calling the main event processing
loop.


<PRE><BR># <B>let</B><CODE> </CODE>go<CODE> </CODE>nbc<CODE> </CODE>nbr<CODE> </CODE>nbm<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>d<CODE> </CODE><CODE>=</CODE><CODE> </CODE>create_minesw<CODE> </CODE>nbc<CODE> </CODE>nbr<CODE> </CODE>nbm<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>loop<CODE> </CODE>d<CODE> </CODE><TT>(</TT>d_init<CODE> </CODE>d<TT>)</TT><CODE> </CODE>d_key<CODE> </CODE><TT>(</TT>d_mouse<CODE> </CODE>d<TT>)</TT><CODE> </CODE><TT>(</TT>d_end<TT>)</TT>;;<BR><CODE>val go : int -&gt; int -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>

The function call <TT>go 10 10 10</TT> builds and starts a game of the
same size as the one depicted in figure&nbsp;<A HREF="book-ora059.html#fig-demineur-ecran">6.5</A>. <BR>
<BR>
<A NAME="toc89"></A>
<H3> Exercises</H3>
This program can be built as a standalone executable program.
Chapter&nbsp;<A HREF="index.html#chap-Compilation">7</A> explains how to do this. Once it is
done, it is useful to be able to specify the size of the game on the
command line. Chapter&nbsp;<A HREF="index.html#chap-Bibliotheques">8</A> describes how to get
command line arguments in an Objective CAML program, and applies it to our
minesweeper (see page&nbsp;<A HREF="book-ora076.html#sec-module-arg">??</A>).<BR>
<BR>
Another possible extension is to have the machine play to discover the
mines. To do this, one needs to be able to find the safe moves and play
them first, then compute the probabilities of presence of a mine
and open the cell with the smallest probability.


<BR>
<BR>
<BR>
<BR>
<HR>
<A HREF="book-ora058.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora061.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
